package com.platform.common.authentication;


import com.platform.common.authentication.params.StatelessParams;
import com.platform.common.authentication.repository.TokenRepository;
import com.platform.common.authentication.repository.impl.RedisTokenRepositoryImpl;
import com.platform.common.authentication.stateless.StatelessAuthFilter;
import com.platform.common.authentication.stateless.StatelessDefaultSubjectFactory;
import com.platform.common.authentication.stateless.StatelessRealm;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.session.mgt.DefaultSessionManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.MethodInvokingFactoryBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.HashMap;
import java.util.Map;

/**
 * 无状态授权配置
 * <p>
 *
 * @description:
 * @author: WangYang
 * @date: 2017-09-28 13:47
 */
@Configuration
@ComponentScan
public class StatelessAuthConfig {

    /**
     * 默认token存储实现
     *
     * @return
     */
    @Bean
    @ConditionalOnMissingBean(TokenRepository.class)
    public TokenRepository tokenRepository() {
        return new RedisTokenRepositoryImpl();
    }

    /**
     * 创建statelessRealm
     *
     * @return
     */
    @Bean
    @ConditionalOnMissingBean(StatelessRealm.class)
    public StatelessRealm statelessRealm() {
        return new StatelessRealm();
    }

    /**
     * session管理 默认禁用
     *
     * @return
     */
    @Bean
    public DefaultSessionManager sessionManager() {
        DefaultSessionManager sessionManager = new DefaultSessionManager();
        //session禁用
        sessionManager.setSessionValidationSchedulerEnabled(false);
        return sessionManager;
    }

    /**
     * 重写凭证 禁用session
     *
     * @return
     */
    @Bean
    public StatelessDefaultSubjectFactory subjectFactory() {
        return new StatelessDefaultSubjectFactory();
    }

    /**
     * 创建SecurityManager
     *
     * @return
     */
    @Bean
    public DefaultSecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 设置realm.
        securityManager.setRealm(statelessRealm());
        // 自定义session管理 使用redis
        securityManager.setSessionManager(sessionManager());
        // 禁用session
        securityManager.setSubjectFactory(subjectFactory());
        DefaultSubjectDAO subjectDAO = (DefaultSubjectDAO) securityManager.getSubjectDAO();
        DefaultSessionStorageEvaluator sessionStorageEvaluator =
                (DefaultSessionStorageEvaluator) subjectDAO.getSessionStorageEvaluator();
        sessionStorageEvaluator.setSessionStorageEnabled(false);
        return securityManager;
    }

    /**
     * 开启shiro aop注解支持.
     * 使用代理方式;所以需要开启代码支持;
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
        AuthorizationAttributeSourceAdvisor sourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        sourceAdvisor.setSecurityManager(securityManager());
        return sourceAdvisor;
    }

    /**
     * 保证实现了Shiro内部lifecycle函数的bean执行
     */
    @Bean
    public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    /**
     * 得到SecurityManager实例 并绑定给SecurityUtils
     *
     * @return
     */
    @Bean
    public MethodInvokingFactoryBean methodInvokingFactoryBean() {
        MethodInvokingFactoryBean factoryBean = new MethodInvokingFactoryBean();
        factoryBean.setStaticMethod("org.apache.shiro.SecurityUtils.setSecurityManager");
        factoryBean.setArguments(new Object[]{securityManager()});
        return factoryBean;
    }

    /**
     * 默认拦截器规则
     *
     * @return
     */
    @Bean
    @ConditionalOnMissingBean(StatelessParams.class)
    public StatelessParams statelessParams() {
        StatelessParams statelessParams = new StatelessParams();
        Map<String, Filter> filterMap = new HashMap<>();
        filterMap.put("statelessAuth", new StatelessAuthFilter());

        Map<String, String> filterChainMap = new HashMap<>();
        filterChainMap.put("/login", "anon");
        filterChainMap.put("/**", "statelessAuth");

        statelessParams.setFilterMap(filterMap);
        statelessParams.setFilterChainMap(filterChainMap);
        return statelessParams;

    }

    /**
     * 拦截器工厂
     *
     * @param securityManager
     * @param statelessParams
     * @return
     */
    @Bean
    public ShiroFilterFactoryBean shirFilter(@Qualifier("securityManager") DefaultSecurityManager securityManager,
                                             @Qualifier("statelessParams") StatelessParams statelessParams) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        // 必须设置 SecurityManager
        shiroFilterFactoryBean.setFilters(statelessParams.getFilterMap());
        //拦截器 配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了
        shiroFilterFactoryBean.setFilterChainDefinitionMap(statelessParams.getFilterChainMap());
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        return shiroFilterFactoryBean;
    }


}
